/**
 * 
 */
package org.t2.game.server.module.rank.service;

import java.util.List;

import org.gaming.prefab.rank.top.TopComparator;
import org.gaming.prefab.rank.top.TopList;
import org.gaming.service.repository.IRepository;
import org.gaming.service.repository.Repository;
import org.gaming.tool.DateTimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.t2.game.server.module.rank.constant.RankType;
import org.t2.game.server.module.rank.model.Ranker;

/**
 * 
 */
public class RankerContext {
	
	private static Logger logger = LoggerFactory.getLogger(RankerContext.class);
	
	private static TopComparator<Ranker> SORTER = new TopComparator<Ranker>() {
		@Override
		public int compara(Ranker o1, Ranker o2) {
			//倒序
			int result = Long.compare(o2.getScore(), o1.getScore());
			if (result != 0) {
				return result;
			}
			//倒序
			result = Long.compare(o2.getSubScore(), o1.getSubScore());
			if (result != 0) {
				return result;
			}
			//升序
			result = Long.compare(o1.getTime(), o2.getTime());
			if (result != 0) {
				return result;
			}
			//升序
			return Long.compare(o1.getPlayerId(), o2.getPlayerId());
		}

		@Override
		public int sdscmp(Ranker o1, Ranker o2) {
			return Long.compare(o1.getPlayerId(), o2.getPlayerId());
		}
	};

	private final RankType rankType;
	
	public RankerContext(RankType rankType) {
		this.rankType = rankType;
	}
	
	//topN中的Ranker对象跟CacheRepository中的Ranker对象会出现不是同一个对象的情况
	private TopList<Ranker> topN;
	private IRepository<Ranker> repository;
	private IRepository<Ranker> repository() {
		if (repository == null) {
			repository = Repository.get(Ranker.class);
		}
		return repository;
	}
	
	public TopComparator<Ranker> getComparator() {
		return SORTER;
	}

	/**
	 * 清理排行榜
	 */
	public void clearRank() {
		topN.clear();
	}
	
	/**
	 * 清理排行榜并删除排行榜数据
	 */
	public void clearRankAndDb() {
		List<Ranker> rankers = getAll();
		repository().deleteAll(rankers);
		topN.clear();
	}
	
	public List<Ranker> getAll() {
		return topN.getElementsByRange(1, topN.getLength());
	}

	public void initRankList(List<Ranker> rankers) {
		this.topN = new TopList<>(this.getComparator());
		for (Ranker ranker : rankers) {
			topN.insert(ranker);
		}
		logger.info("初始化排行榜{}数据数量{}", this.rankType, rankers.size());
	}

	/**
	 * 根据实体ID获取排名对象
	 *
	 * @param playerId
	 * @return
	 */
	public Ranker getRanker(long playerId) {
		return this.repository().getByKeys(this.rankType.getValue() + "_" + playerId);
	}

	/**
	 * 根据实体对象获取排名名次
	 *
	 * @param ranker
	 * @return
	 */
	public int getRank(Ranker ranker) {
		return topN.getRank(ranker);
	}

	/**
	 * 根据实体ID获取排名名次
	 *
	 * @param playerId
	 * @return
	 */
	public int getRank(long playerId) {
		Ranker ranker = this.getRanker(playerId);
		if (ranker == null) {
			return 0;
		}
		return topN.getRank(ranker);
	}

	/**
	 * 获取从rankMin到rankMax排名的数据，rankMin从1开始
	 *
	 * @param rankMin
	 * @param rankMax
	 * @return
	 */
	public List<Ranker> getTopN(int rankMin, int rankMax) {
		return topN.getElementsByRange(rankMin, rankMax);
	}

	/**
	 * 更新排行榜
	 * 先从排行榜中删除元素，再插入排行数据
	 *
	 * @param playerId
	 * @param score
	 * @param subScore
	 * @param time
	 */
	public synchronized void updateRank(long playerId, long score, long subScore, String extraData) {
		Ranker ranker = this.getRanker(playerId);
		if (ranker != null) {
			topN.delete(ranker);

			ranker.setScore(score);
			ranker.setSubScore(subScore);
			ranker.setExtraData(extraData);
			ranker.setTime(DateTimeUtil.currMillis());
			this.repository().update(ranker);
		} else {
			ranker = new Ranker();
			ranker.setId(this.rankType.getValue() + "_" + playerId);
			ranker.setType(this.rankType.getValue());
			ranker.setPlayerId(playerId);
			ranker.setScore(score);
			ranker.setSubScore(subScore);
			ranker.setExtraData(extraData);
			ranker.setTime(DateTimeUtil.currMillis());
			this.repository().insert(ranker);
		}
		topN.insert(ranker);
	}
	
	public synchronized Ranker deleteRank(long playerId) {
		Ranker ranker = this.getRanker(playerId);
		if(ranker != null) {
			topN.delete(ranker);
		}
		return ranker;
	}

	public RankType getRankType() {
		return rankType;
	}
}
